home *** CD-ROM | disk | FTP | other *** search
- //////////
- //
- // File: QDrawHandler.c
- //
- // Contains: Code for creating a derived media handler component for QuickDraw pictures.
- //
- // Written by: Tim Monroe
- // Based on MyMediaComponent by John Wang (see develop issue 14), with some
- // assistance from SampleMediaHandler by deeje cooley.
- //
- // Copyright: © 1993-1999 by Apple Computer, Inc., all rights reserved.
- //
- // Change History (most recent first):
- //
- // <7> 02/25/99 rtm added some comments
- // <6> 01/28/99 rtm fixed bug that caused garbage to be drawn when Copy menu item selected
- // or a drag of movie clipping attempted
- // <5> 01/25/99 rtm got Windows DLL working
- // <4> 01/21/99 rtm got both MacOS PPC and 68K versions working
- // <3> 01/15/99 rtm coordinated with SampleMediaHandler by deeje cooley
- // <2> 01/05/99 rtm revised coding style
- // <1> 02/25/93 jw first file; based on MyComponent shell
- //
- // This project builds a derived (or custom) media handler. See the chapter "Derived Media Handler
- // Components" in the book Inside Macintosh: QuickTime Components for information about writing
- // derived media handler components. See also John Wang's article on derived media handlers in develop,
- // issue 14, for more information about the QuickDraw media handler. The main difference between his
- // code and the current sample code is that I've made the dispatching routines both PPC- and Windows-savvy,
- // using the ComponentDispatchHelper code. Also fixed a few bugs and added some more comments.
- //
- //////////
-
-
- //////////
- //
- // header files
- //
- //////////
-
- #include "QDrawHandler.h"
-
-
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // Component dispatch helper defines
- //
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
- #if TARGET_CPU_68K
- #define COMPONENT_C_DISPATCHER
- #define COMPONENT_DISPATCH_MAIN
- #endif
-
- #define MEDIA_BASENAME() QDMH_
- #define MEDIA_GLOBALS() QDMH_GlobalsHdl storage
-
- #define CALLCOMPONENT_BASENAME() MEDIA_BASENAME()
- #define CALLCOMPONENT_GLOBALS() MEDIA_GLOBALS()
-
- #define COMPONENT_UPP_PREFIX() uppMedia
- #define COMPONENT_SELECT_PREFIX() kMedia
- #define COMPONENT_DISPATCH_FILE "QDrawHandlerDispatch.h"
-
- #define GET_DELEGATE_COMPONENT() ((**storage).fDelegate)
-
- #include "Components.k.h"
- #include "MediaHandlers.k.h"
- #include "ComponentDispatchHelper.c"
-
-
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // Required component calls
- //
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
- //////////
- //
- // QDMH_Open
- // Open the derived media handler component.
- //
- //////////
-
- PASCAL_RTN ComponentResult QDMH_Open (QDMH_GlobalsHdl storage, ComponentInstance theSelf)
- {
- #pragma unused(storage)
-
- QDMH_GlobalsHdl myStorage = NULL;
- ComponentInstance myComponent = NULL;
-
- // allocate the private global storage used by this component instance
- myStorage = (QDMH_GlobalsHdl)NewHandleClear(sizeof(QDMH_Globals));
- if (myStorage == NULL)
- return(MemError());
-
- SetComponentInstanceStorage(theSelf, (Handle)myStorage);
-
- // open the base media handler component and target it
- myComponent = OpenDefaultComponent(MediaHandlerType, BaseMediaType);
- if (myComponent == NULL)
- return(componentNotCaptured);
-
- ComponentSetTarget(myComponent, theSelf);
-
- (**myStorage).fDelegate = myComponent;
- (**myStorage).fSelf = theSelf;
- (**myStorage).fParent = theSelf;
-
- return(noErr);
- }
-
-
- //////////
- //
- // QDMH_Close
- // Close the derived media handler component.
- //
- //////////
-
- PASCAL_RTN ComponentResult QDMH_Close (QDMH_GlobalsHdl storage, ComponentInstance theSelf)
- {
- #pragma unused(theSelf)
-
- if (storage != NULL) {
-
- // close the base media handler component instance
- if ((**storage).fDelegate != NULL)
- CloseComponent((**storage).fDelegate);
-
- // dispose of the private global storage created by the _Open routine
- DisposeHandle((Handle)storage);
- }
-
- return(noErr);
- }
-
-
- //////////
- //
- // QDMH_Version
- // Return the version of the derived media handler component.
- //
- //////////
-
- PASCAL_RTN ComponentResult QDMH_Version (QDMH_GlobalsHdl storage)
- {
- #pragma unused(storage)
-
- return(kQDMH_Version);
- }
-
-
- //////////
- //
- // QDMH_Register
- // Register.
- //
- // This routine is called once (usually at boot time) when the Component Manager first
- // registers this component. Note that the cmpWantsRegisterMessage bit must be set in
- // the component flags of the component in order for this routine to be called.
- //
- //////////
-
- PASCAL_RTN ComponentResult QDMH_Register (QDMH_GlobalsHdl storage)
- {
- if (storage != NULL)
- return(noErr); // globals properly set up: the base media handler was targeted OK
- else
- return(-1); // globals not properly set up: don't register
- }
-
-
- //////////
- //
- // QDMH_Target
- // Target.
- //
- //////////
-
- PASCAL_RTN ComponentResult QDMH_Target (QDMH_GlobalsHdl storage, ComponentInstance theTarget)
- {
- // remember who is at the top of our calling chain
- (**storage).fParent = theTarget;
-
- // inform the base media handler of the change
- ComponentSetTarget((**storage).fDelegate, theTarget);
-
- return(noErr);
- }
-
-
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // Derived media handler functions
- //
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
- //////////
- //
- // QDMH_Initialize
- // Initialize our media handler.
- //
- //////////
-
- PASCAL_RTN ComponentResult QDMH_Initialize (QDMH_GlobalsHdl storage, GetMovieCompleteParams *theGMC)
- {
- ComponentResult myErr = noErr;
- long myFlags;
-
- if ((storage == NULL) || (theGMC == NULL))
- return(paramErr);
-
- // set general characteristics
- (**storage).fMovie = theGMC->theMovie;
- (**storage).fTrack = theGMC->theTrack;
- (**storage).fMedia = theGMC->theMedia;
- (**storage).fCurMediaRate = theGMC->effectiveRate;
- MacSetRect(&((**storage).fGraphicsBox), 0, 0, (short)(theGMC->width >> 16), (short)(theGMC->height >> 16));
- (**storage).fTrackMatrix = theGMC->trackMovieMatrix;
- (**storage).fPort = theGMC->moviePort;
- (**storage).fDevice = theGMC->movieGD;
- (**storage).fSampleDescIndex = -1;
-
- // set media globals
- (**storage).fWhatChanged = kQDMHAllChanged;
- (**storage).fEnabled = false;
- (**storage).fNewMediaRate = theGMC->effectiveRate;
- (**storage).fPrevMediaTime = -1;
-
- // inform the base media handler of our capabilities:
- // * handlerHasSpatial indicates that we draw
- // * handlerNeedsBuffer indicates that we want QuickTime to maintain a drawing buffer for us
- myFlags = handlerHasSpatial | handlerNeedsBuffer;
- myErr = MediaSetHandlerCapabilities((**storage).fDelegate, myFlags, -1);
-
- return(myErr);
- }
-
-
- //////////
- //
- // QDMH_Idle
- // Draw our media sample.
- //
- // Here is where we get time to process the current media sample data. In our case, we want to extract
- // the QuickDraw picture data from the media and draw it into the current graphics port. If the sample
- // data consisted of a complete QuickDraw picture, we could get that picture by calling GetMediaSample
- // and then draw the picture by calling MacSetRect, TransformRect, and DrawPicture. (This is the route
- // taken in the derived media handler described in Inside Macintosh: QuickTime Components, pp. 10-9 to
- // 10-14.) Our media handler, however, supports key frames (also called sync frames), which complicate
- // the work we need to do here. A key frame is a sample that does not rely on previous samples for any
- // of its information. A non-key frame (or difference frame) contains just data that has changed from
- // the previous frame.
- //
- //////////
-
- PASCAL_RTN ComponentResult QDMH_Idle (QDMH_GlobalsHdl storage, TimeValue theMediaTime, long theFlagsIn, long *theFlagsOut, const TimeRecord *theMovieTime)
- {
- #pragma unused(theMovieTime)
-
- Media myMedia = (**storage).fMedia;
- TimeValue myPrevMediaTime = (**storage).fPrevMediaTime;
- long myWhatChanged; // flags indicating changes in media environment
- GDHandle mySavedGD;
- CGrafPtr mySavedPort;
- Rect myDrawRect;
- Boolean myRedraw; // do we need to draw anything?
- Boolean myIsDone;
- TimeValue myTime;
- long mySize;
- PicHandle mySyncPic = NULL;
- PicHandle myCurrPic = NULL;
- TimeValue mySyncSampleTime;
- TimeValue myCurrSampleTime;
- long myCurrSampleIndex;
- OSErr myErr = noErr;
-
- //////////
- //
- // inspect theFlagsIn to determine what the Movie Toolbox wants us to do
- //
- //////////
-
- // don't draw anything if mPreflightDraw flag is set
- if (theFlagsIn & mPreflightDraw)
- return(myErr);
-
- //////////
- //
- // initialize
- //
- //////////
-
- // allocate space for two pictures (the current sample's picture and the previous sync frame);
- // GetMediaSample resizes these handles as necessary when returning the media data
- mySyncPic = (PicHandle)NewHandle(sizeof(Picture));
- myCurrPic = (PicHandle)NewHandle(sizeof(Picture));
- if ((mySyncPic == NULL) || (myCurrPic == NULL)) {
- myErr = memFullErr;
- goto bail;
- }
-
- GetGWorld(&mySavedPort, &mySavedGD);
- SetGWorld((GWorldPtr)(**storage).fPort, (**storage).fDevice);
-
- //////////
- //
- // get information about the current sample
- //
- //////////
-
- myErr = GetMediaSample(myMedia, (Handle)myCurrPic, 0, NULL, theMediaTime, &myCurrSampleTime, NULL, NULL, &myCurrSampleIndex, 0, NULL, NULL);
- if (myErr != noErr)
- goto bail;
-
- // check to see whether the sample description index has changed since the last sample
- if (myCurrSampleIndex != (**storage).fSampleDescIndex) {
- (**storage).fSampleDescIndex = myCurrSampleIndex;
- (**storage).fWhatChanged |= kQDMHSampleDescChanged;
- }
-
- //////////
- //
- // determine what, if anything, in the media has changed
- // (we don't need to draw the current media sample if nothing has changed)
- //
- //////////
-
- myRedraw = false;
- myWhatChanged = (**storage).fWhatChanged;
-
- if (myWhatChanged != kQDMHNothingChanged) {
-
- if (myWhatChanged & kQDMHSetActive) // if media was just enabled, then redraw; else don't change
- myRedraw = (**storage).fEnabled;
-
- if (myWhatChanged & kQDMHSetRate) {
- // if we are now playing in the opposite direction, then redraw
- if ((((**storage).fCurMediaRate < 0) && ((**storage).fNewMediaRate > 0))
- || (((**storage).fCurMediaRate > 0) && ((**storage).fNewMediaRate < 0)))
- myRedraw = true;
- (**storage).fCurMediaRate = (**storage).fNewMediaRate;
- }
-
- if (myWhatChanged & kQDMHTrackEdited)
- myRedraw = true; // if track edited, then redraw
-
- if (myWhatChanged & kQDMHSetGWorld)
- myRedraw = true; // if new GWorld, then redraw
-
- if (myWhatChanged & kQDMHSetDimensions)
- myRedraw = true; // if new dimensions, then redraw
-
- if (myWhatChanged & kQDMHSetMatrix)
- myRedraw = true; // if new matrix, then redraw
-
- if (myWhatChanged & kQDMHSampleDescChanged) {
- QDrawDescriptionHandle myQDDesc;
-
- // the sample description has changed; make sure it's a version we can handle
- myQDDesc = (QDrawDescriptionHandle)NewHandleClear(sizeof(QDrawDescription));
- if (myQDDesc != NULL) {
- GetMediaSampleDescription(myMedia, (**storage).fSampleDescIndex, (SampleDescriptionHandle)myQDDesc);
- #if HANDLER_SWAPS_SAMPLE_DESC
- if ((**myQDDesc).version > kQDMH_Version)
- #else
- if ((**myQDDesc).version > EndianU32_NtoB(kQDMH_Version))
- #endif
- (**storage).fEnabled = false;
- DisposeHandle((Handle)myQDDesc);
- } else {
- (**storage).fEnabled = false;
- }
- }
-
- // clear out flags indicating changes in media environment
- (**storage).fWhatChanged = kQDMHNothingChanged;
- }
-
- // if we are playing the movie backwards, we must always redraw from last sync frame
- if ((**storage).fCurMediaRate < 0)
- myRedraw = true;
-
- //////////
- //
- // we do not need to draw anything if myRedraw is false and if myPrevMediaTime == myCurrSampleTime
- // (since we've already drawn that sample and nothing has occurred to cause us to have to redraw it)
- //
- // otherwise, we do need to draw; what we draw depends on the value of myRedraw:
- // (a) if myRedraw = true, redraw everything since the previous key frame
- // (b) if myRedraw = false, redraw everything since the previous key frame or the previous media frame,
- // whichever is closer to current frame
- //
- //////////
-
- if (myRedraw || (myPrevMediaTime != myCurrSampleTime)) {
-
- // find the previous key frame; note that we use the nextTimeEdgeOK flag, since the current frame
- // might be a key frame; note also that if the media doesn't contain any key frames, the sample
- // time returned in mySyncSampleTime is the same as myCurrSampleTime (that is, every frame is a key
- // frame)
-
- GetMediaNextInterestingTime(myMedia, nextTimeSyncSample + nextTimeEdgeOK, myCurrSampleTime, -1, &mySyncSampleTime, NULL);
-
- // if myRedraw = false, mySyncSampleTime <= myPrevMediaTime, and myCurrSampleTime is ahead of
- // myPrevMediaTime, then search to set the place to draw as the sample after myPrevMediaTime
- if (!myRedraw && (mySyncSampleTime <= myPrevMediaTime) && (myPrevMediaTime < myCurrSampleTime)) {
- myTime = mySyncSampleTime;
-
- while ((myTime >= 0) && (myTime < myPrevMediaTime))
- GetMediaNextInterestingTime(myMedia, nextTimeMediaSample, myTime, 1, &myTime, NULL);
-
- if ((myTime == myPrevMediaTime) && (myTime != -1)) {
- GetMediaNextInterestingTime(myMedia, nextTimeMediaSample, myTime, 1, &myTime, NULL);
- if (myTime != -1)
- mySyncSampleTime = myTime;
- }
- }
-
- //////////
- //
- // draw the picture, beginning at mySyncSampleTime; but don't draw if the media is disabled
- //
- //////////
-
- myIsDone = false;
- myTime = mySyncSampleTime;
- while (!myIsDone && (**storage).fEnabled) {
-
- if (myTime == myCurrSampleTime)
- myIsDone = true;
-
- myErr = GetMediaSample(myMedia, (Handle)mySyncPic, 0, &mySize, myTime, NULL, NULL, NULL, NULL, 0, NULL, NULL);
- if (myErr != noErr)
- goto bail;
-
- myDrawRect = (**storage).fGraphicsBox;
- TransformRect(&(**storage).fTrackMatrix, &myDrawRect, NULL);
- DrawPicture(mySyncPic, &myDrawRect);
- if (!myIsDone) {
- GetMediaNextInterestingTime(myMedia, nextTimeMediaSample, myTime, 1, &myTime, NULL);
- if (myTime < 0)
- myIsDone = true;
- }
- }
-
- // say we drew somthing
- *theFlagsOut |= mDidDraw;
- }
-
- // update the previous media time
- (**storage).fPrevMediaTime = myCurrSampleTime;
-
- //////////
- //
- // clean up and return
- //
- //////////
-
- bail:
- SetGWorld((GWorldPtr)mySavedPort, mySavedGD);
-
- if (mySyncPic != NULL)
- DisposeHandle((Handle)mySyncPic);
- if (myCurrPic != NULL)
- DisposeHandle((Handle)myCurrPic);
-
- return(myErr);
- }
-
-
- //////////
- //
- // QDMH_SetActive
- // Set the enabled state of the media.
- //
- //////////
-
- PASCAL_RTN ComponentResult QDMH_SetActive (QDMH_GlobalsHdl storage, Boolean theEnableMedia)
- {
- if ((**storage).fEnabled != theEnableMedia) {
- (**storage).fEnabled = theEnableMedia;
- (**storage).fWhatChanged |= kQDMHSetActive;
- }
-
- return(noErr);
- }
-
-
- //////////
- //
- // QDMH_SetRate
- // Set the media rate.
- //
- //////////
-
- PASCAL_RTN ComponentResult QDMH_SetRate (QDMH_GlobalsHdl storage, Fixed theRate)
- {
- // save the new rate in fNewMediaRate so that we can compare with previous rate;
- // if the new rate is in the same direction, we won't want to redraw again from the previous key frame
- if ((**storage).fNewMediaRate != theRate) {
- (**storage).fNewMediaRate = theRate;
- (**storage).fWhatChanged |= kQDMHSetRate;
- }
-
- return(noErr);
- }
-
-
- //////////
- //
- // QDMH_TrackEdited
- // Set the track-edited state.
- //
- //////////
-
- PASCAL_RTN ComponentResult QDMH_TrackEdited (QDMH_GlobalsHdl storage)
- {
- (**storage).fWhatChanged |= kQDMHTrackEdited;
-
- return(noErr);
- }
-
-
- //////////
- //
- // QDMH_SetGWorld
- // Set the media graphics port.
- //
- //////////
-
- PASCAL_RTN ComponentResult QDMH_SetGWorld (QDMH_GlobalsHdl storage, CGrafPtr thePort, GDHandle theGD)
- {
- (**storage).fPort = thePort;
- (**storage).fDevice = theGD;
- (**storage).fWhatChanged |= kQDMHSetGWorld;
-
- return(noErr);
- }
-
-
- //////////
- //
- // QDMH_SetDimensions
- // Set the media dimensions.
- //
- //////////
-
- PASCAL_RTN ComponentResult QDMH_SetDimensions (QDMH_GlobalsHdl storage, Fixed theWidth, Fixed theHeight)
- {
- MacSetRect(&((**storage).fGraphicsBox), 0, 0, (short)(theWidth >> 16), (short)(theHeight >> 16));
- (**storage).fWhatChanged |= kQDMHSetDimensions;
-
- return(noErr);
- }
-
-
- //////////
- //
- // QDMH_SetMatrix
- // Set the track or movie matrix.
- //
- //////////
-
- PASCAL_RTN ComponentResult QDMH_SetMatrix (QDMH_GlobalsHdl storage, MatrixRecord *theTrackMovieMatrix)
- {
- // don't cause unnecessary updates if the matrix doesn't really change
- // (this can happen if the resize button is clicked on, but not moved)
- if (!EqualMatrix(&((**storage).fTrackMatrix), theTrackMovieMatrix)) {
- (**storage).fTrackMatrix = *theTrackMovieMatrix;
- (**storage).fWhatChanged |= kQDMHSetMatrix;
- }
-
- return(noErr);
- }
-
-
- //////////
- //
- // QDMH_SampleDescriptionChanged
- // Handle changes to the sample description tables.
- //
- //////////
-
- PASCAL_RTN ComponentResult QDMH_SampleDescriptionChanged (QDMH_GlobalsHdl storage, long theIndex)
- {
- // the sample description tables store info such as data version
- (**storage).fSampleDescIndex = theIndex;
- (**storage).fWhatChanged |= kQDMHSampleDescChanged;
-
- return(noErr);
- }
-
-
- #if HANDLER_SWAPS_SAMPLE_DESC
- //////////
- //
- // QDMH_SampleDescriptionB2N
- // Convert our sample description from big- to native-endian format.
- //
- //////////
-
- PASCAL_RTN ComponentResult QDMH_SampleDescriptionB2N (QDMH_GlobalsHdl storage, SampleDescriptionHandle theSampleDesc)
- {
- #pragma unused(storage)
-
- QDrawDescriptionHandle myQDDesc = (QDrawDescriptionHandle)theSampleDesc;
-
- if ((myQDDesc == NULL) || (*myQDDesc == NULL))
- return(paramErr);
-
- // (**myQDDesc).size = EndianU32_BtoN((**myQDDesc).size);
- // (**myQDDesc).type = EndianU32_BtoN((**myQDDesc).type);
- // (**myQDDesc).resvd1 = EndianU32_BtoN((**myQDDesc).resvd1);
- // (**myQDDesc).resvd2 = EndianU16_BtoN((**myQDDesc).resvd2);
- // (**myQDDesc).dataRefIndex = EndianU16_BtoN((**myQDDesc).dataRefIndex);
- (**myQDDesc).version = EndianU32_BtoN((**myQDDesc).version);
-
- return(noErr);
- }
-
-
- //////////
- //
- // QDMH_SampleDescriptionN2B
- // Convert our sample description from native- to big-endian format.
- //
- //////////
-
- PASCAL_RTN ComponentResult QDMH_SampleDescriptionN2B (QDMH_GlobalsHdl storage, SampleDescriptionHandle theSampleDesc)
- {
- #pragma unused(storage)
-
- QDrawDescriptionHandle myQDDesc = (QDrawDescriptionHandle)theSampleDesc;
-
- if ((myQDDesc == NULL) || (*myQDDesc == NULL))
- return(paramErr);
-
- // (**myQDDesc).size = EndianU32_NtoB((**myQDDesc).size);
- // (**myQDDesc).type = EndianU32_NtoB((**myQDDesc).type);
- // (**myQDDesc).resvd1 = EndianU32_NtoB((**myQDDesc).resvd1);
- // (**myQDDesc).resvd2 = EndianU16_NtoB((**myQDDesc).resvd2);
- // (**myQDDesc).dataRefIndex = EndianU16_NtoB((**myQDDesc).dataRefIndex);
- (**myQDDesc).version = EndianU32_NtoB((**myQDDesc).version);
-
- return(noErr);
- }
- #endif // HANDLER_SWAPS_SAMPLE_DESC
-